home *** CD-ROM | disk | FTP | other *** search
-
- odin's_________ _______ ______ _____________
- ____\ /____\ /________\ /____| /_____/_______ _________
- / _____/ _____/ __ ___/ '____/ / | \ _____/___
- / | \ || | | | \ . \ | | | \__ /
- \_____ \___| \____ |____ \___| \___|____| |_____ |
- |_______/ <hook> `----' |_____/ |______/ |____| |_____|
- tutorial v1.51
-
- Cracking/Patching SoftArt's Deskey v1.02.010
-
- X. TABLE OF CONTENTS
-
- 1. FOREWARDS
- 2. INTRODUCTION
- 3. TOOLS USED FOR THIS
- 4. THE CRACKING STARTS
- 5. MAKING A PATCH
- 6. THE URL'S
-
- 1. Forewards
-
- Welcome. So how come you're interested in reading this tutorial?
- Perhaps you think cracking is cool and seems easy, and that cracking
- is a way to be famous on the internet today. Well, if you think like
- this please stop reading now. Why? Mainly because most crackers don't
- crack because they think it's "cool." and want to be famous. Cracking
- is something they actually do because they think its a great thing to
- spend their precious time on, believe it or not. Most crackers, not to
- say all, also code in one or several computer languages.
-
- On the other hand if you're very interested in how computers work
- internally, and you like to program in languages like Pascal, C++ and
- Assembler, then I believe this tutorial is worth reading for people
- such as you, and you might even learn something from it.
-
- If you're the third category, you've been learning cracking for some
- time now and read every little article about cracking you can get,
- then this tutorial also is very good to read. You can always learn
- something that you didn't know before. Even I can learn things I
- didn't know by listening to others and reading various text files.
-
- To become a cracker will take several years. And to become a good
- cracker will take even longer. The key to success is practice and, in
- my point of view, learning and listening to other crackers.
-
- I'll skip the most things about how SoftICE works because there are
- several good tutorials out about that. One is Exact's SoftICE
- tutorial, very good and recommended reading.
-
- 2. Introduction
-
- This text files purpose is to show and hopefully learn you how to
- patch away a time limit of a program. The program we will use is
- SoftArt's Deskey. It isn't necessary to patch this program because you
- can also enter a registration code in the registry to get the program
- to work fully, but then you have to write a keymaker because the code
- depends on the Windows name and company (the one you enter when you
- installed Windows 95). So we're going to do it the lazy way and patch
- it. There are of course other ways to do this crack.
-
- 3. Tools you will need for this
-
- (1) SoftICE 2.0/3.0, of course, our beloved debugger.
-
- (2) Ultra Edit or another good hex editor.
-
- (3) A patch generator, or if you write the patch yourself as I do.
-
- 4. The cracking starts
-
- Ok, let's begin with removing the semicolon from the user32.dll and
- kernel32.dll lines in SOFTICE.DAT if you haven't done so already.
-
- Now let's do some detective work, by checking the Deskey help file.
- You'll notice that this program will stop working after 60 minutes.
- This limit is what we're going to remove. There are a few possible
- solutions for the programmer to obtain this limit. To check which
- functions the program use, let's test the approach Qapla used in his
- tutorial:
-
- Start the explorer and press the right mouse button on the Deskey exe
- file. Now choose Quick-View. You'll notice all the calls the program
- uses and which dll's store the code for the calls. When you look at
- them, you'll notice some interesting functions.
-
- Import Table
-
- ...
- KERNEL32.dll
- Ordinal Function Name
- ... ...
- 008f FreeLibrary
- 0188 MultiByteToWideChar
- 011d GetSystemTime <----- Interesting
- 00e4 GetLocalTime <----- Interesting
- 025d lstrcmpiA
- 00ca GetDateFormatA
- ... ...
-
- USER32.dll
- Ordinal Function Name
- ... ...
- 00ec GetDlgItemTextA
- 007d DefWindowProcA
- 01fe SetTimer <----- Interesting
- 01a2 PostMessageA
- 0224 TrackPopupMenu
- 01b8 RemoveMenu
- ... ...
-
- Ok, as you see I'm interested in 3 different calls. We can try to see
- if the program uses KERNEL32!GetSystemTime(); and
- KERNEL32!GetLocalTime();. Enter SoftICE and put a breakpoint on these
- two. Enable them just when you're about to start the program. If you
- do it before, you risc to break on these calls used by another
- program. So just before you start Deskey, enable these.
-
- Now you started it and program pops up in the traybar. Nothing
- happens. Oh well, then we can exclude these ones. Actually a cracker
- might have excluded them from the beginning and tried some other calls
- first. Why? Probably because a programmer usually uses these calls if
- the program has a 30-day limit, not a 60-minutes one.
-
- We have one left to test, USER32!SetTimer();. Exit Deskey and put a
- breakpoint on SetTimer(); just before you start Deskey.
-
- Finally, SoftICE detected the use of this function by Deskey. Press
- F11. It should look something like this now:
-
- .
- .
- .
- 0137:0040397F 833D1890400000 CMP DWORD PTR [00409018], 00
- 0137:00403986 7409 JZ 00403991
- 0137:00403988 833D1C90400000 CMP DWORD PTR [0040901C], 00
- 0137:0040398F 7421 JZ 004039B2
- 0137:00403991 6A00 PUSH 00
- 0137:00403993 A128904000 MOV EAX,[00409028]
- 0137:00403998 6880EE3600 PUSH 0036EE80
- 0137:0040399D 6834120000 PUSH 00001234
- 0137:004039A2 50 PUSH EAX
- 0137:004039A3 FF158CB44000 CALL [USER32!SetTimerA] <-- you're here
- 0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
- 0137:004039B0 EB12 JMP 004039C4
- 0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
- 0137:004039B0 EB09 JMP 004039C4
- 0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
- 0137:004039B0 EB07 JMP 004039CB
- .
- .
- .
-
- Let's check the SetTimerA function in our we-cant-be-without-it API
- guide:
-
- The SetTimer function creates a timer with the specified time-out value.
-
- UINT SetTimer(
- HWND hwnd, // handle of window for timer messages
- UINT idTimer, // timer identifier
- UINT uTimeout, // time-out value
- TIMERPROC tmprc // address of timer procedure
- );
- .
- .
- .
- uTimeout
- Specifies the time-out value, in milliseconds.
- .
- .
- .
-
- Aha, let's check on the code again:
-
- 0137:00403991 6A00 PUSH 00 <-- tmprc
- 0137:00403993 A128904000 MOV EAX,[00409028] <-- pushed later
- 0137:00403998 6880EE3600 PUSH 0036EE80 <-- uTimeout
- 0137:0040399D 6834120000 PUSH 00001234 <-- idTimer
- 0137:004039A2 50 PUSH EAX <-- HWND
- 0137:004039A3 FF158CB44000 CALL [USER32!SetTimerA] <-- you're here
-
- Hmm, very interesting indeed, let's check the value 0036EE80 in the
- SoftICE debugger:
-
- :? 36ee80
- 0036EE80 0003600000 "6»╟"
-
- An even and nice value. And if you read further in the API help file
- you'll notice that the uTimeout should be in milliseconds. 1 second is
- 1000 milliseconds. Let's do some calculating:
-
- 3600000/1000=3600 seconds.
-
- 60 seconds*60 minutes=3600 seconds, which is 1 hour
-
- We've found the right one! This call creates a timer which will be
- checked when the program process the WM_TIMER message from Windows.
- The WM_TIMER message is sent when 1 hour has past. Let's check the API
- reference once more:
-
- WM_TIMER
-
- wTimerID = wParam; // timer identifier
- tmprc = (TIMERPROC *) lParam; // address of timer callback
-
- The WM_TIMER message is posted to the installing thread's message
- queue or sent to the appropriate TimerProc callback function after
- each interval specified in the SetTimer function used to install a
- timer.
- .
- .
- .
-
- So now we know where he creates the timer. If you remove this
- SetTimer(); call the WM_TIMER message will never be sent, resulting in
- that the 60 minute limit will be REMOVED!! Let's take a look at this
- example code below:
-
- SetTimer(hwnd, idTimer, 0x36EE80, tmprc);
- ^-- hex value
-
- WM_TIMER: { <-- this structure is reached when
- PostQuitMessage(0); the hex value above reach 0. If
- ^-- will exit the program the timer never is set this
- } structure wont be reached.
-
- This is very simple to understand, I hope :-).
-
- So perhaps you think, "hey, let's NOP away the whole structure"
-
- (for those of you not familiar with NOP: it means NO OPERATION
- and are very commonly used when patching. The computer will do
- nothing when it executes this instruction.)
-
- Nono stop! Don't NOP away the whole call. Well first of all a good
- rule when patching is that, never alter the code more then you
- actually need. It looks nice (who'll notice anyway), and it decreases
- the chance of program crash due to doing something stupid. So how
- should we do instead? Well let's check that code once more:
-
- .
- .
- .
- 0137:0040397F 833D1890400000 CMP DWORD PTR [00409018], 00
- 0137:00403986 7409 JZ 00403991
- 0137:00403988 833D1C90400000 CMP DWORD PTR [0040901C], 00
- 0137:0040398F 7421 JZ 004039B2
- 0137:00403991 6A00 PUSH 00
- 0137:00403993 A128904000 MOV EAX,[00409028]
- 0137:00403998 6880EE3600 PUSH 0036EE80
- 0137:0040399D 6834120000 PUSH 00001234
- 0137:004039A2 50 PUSH EAX
- 0137:004039A3 FF158CB44000 CALL [USER32!SetTimerA] <-- you're here
- 0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
- 0137:004039B0 EB12 JMP 004039C4
- 0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
- 0137:004039B0 EB09 JMP 004039C4
- 0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
- 0137:004039B0 EB07 JMP 004039CB
- .
- .
- .
-
- The CMP (compare) instructions above seems very interesting.
-
- As you might notice, the one at 00403986 will jump to 00403991 and
- start the timer. If you check the JZ at 0040398F it will go to
- 004039B2 and therefor jump over the timer, resulting in that there
- will be no time limit. So to solve this simple problem just change the
- JZ 00403991 at 00403986 to JMP 004039B2 instead. Like this:
-
- 0137:00403986 7409 JZ 00403991
- ---> to --->
- 0137:00403986 EB2A JMP 004039B2
-
- Now let's apply the patch to the exe file. Load up your favorite hex
- editor. In this case I'll use Ultra Edit. Now load the exe file.
- Choose search and enter the following bytes: 68 80 EE 36 00.
-
- So why do we search after these? Well that's very easy. Check the code
- once again:
-
- 0137:00403993 A128904000 MOV EAX,[00409028]
- 0137:00403998 6880EE3600 PUSH 0036EE80 <--- this one
- 0137:0040399D 6834120000 PUSH 00001234
-
- As you see these bytes stands for the instruction PUSH 0036EE80.
-
- "Uhu, I don't have those cryptic numbers to the left of my
- instructions!!". Well that's easy to fix. Just write 'code on' and
- you'll see these cryptic numbers, also known as OPerand codes.
-
- "Why didn't you search 83 3D 18 90 40 00 00 for example?". Well that's
- because I know the ones we searched for only exists one time in the
- exe file. The one mentioned above (83 3D...) exists several times, so
- you cannot actually know which of those to use, if you don't check the
- surrounding bytes that is. Always do "search next" so you are sure
- that that byte combination doesn't exist somewhere else in the file.
-
- Now let's change the bytes needed. Some bytes above '68 80 EE 36 00'
- you will find '74 09' which is the JZ 00403991 instruction. This is
- the two bytes we want to change. So how do you know which numbers to
- actually change to? That's also easy. In the debugger when you're
- looking at the code just use the 'a' command. Like This:
-
- 0137:0040397F 833D1890400000 CMP DWORD PTR [00409018], 00
- 0137:00403986 7409 JZ 00403991
- 0137:00403988 833D1C90400000 CMP DWORD PTR [0040901C], 00
- ----------------------------------------^ code window ^ -----
- :a 00403986 JMP 004039B2
- ----------------------------------------^ prompt ^-----------
-
- This will change the instruction at 00403986 and a new code will pop
- up, EB2A. So this is the code you want to change for the 7409 one.
- Remember, that if you use the 'a' command it will not change the code
- permanently, only temporary. That's why we have to use a hex editor.
- So go to the '74 09' bytes and change it to 'EB 2A'.
-
- Now save the exe file, voila! That's it. Now start the program up and
- test if it works. If SoftICE doesn't break on SetTimer(); it probably
- worked. If it does, read this all again :-).
-
- One thing has to be said also. If you for example want to change a
- instruction with the opcode 'C1 E1 10' (3 bytes) to a instruction that
- only has a 2 byte opcode, for example '0B D1', you have to NOP away
- the last byte. NOP has the hex value 90.
-
- Like this:
-
- C1 E1 10 becomes ---> 0B D1 90
- SHL ECX, 10 becomes ---> OR EDX, ECX <- 0B D1
- NOP <- 90
-
- As you see I change the F3 to 90 and therefore put the instruction NOP
- there. If you didn't do this the chance of a program crash would be
- 98%.
-
- That's all. To patch is very simple, but to find the bytes to change
- is harder. Remember that the byte combination can exist somewhere else
- so check the surrounding bytes.
-
- 5. Making the patch
-
- Now it's time to make this patch available to the public. To write
- something like "uhu change the bytes at blabla to blabla" doesn't look
- that good, does it? So now it's time to make a exe file that changes
- those bytes asap so the user don't have to use Ultra Edit every time.
- I've included a program in Pascal done for this task. There are also
- several good patch generators.
-
- One for Windows 95, that I strongly recommend, is Qapla's PatchIt '97.
- It's fast and nice interface (happy now Qapla :-)
-
- To convert this program to C++ should be easy. You have to know one
- more thing to make a patch, where the bytes are located in the file.
- This is called "offset.", to check the offset just go to the bytes you
- changed, and look at the status bar in Ultra Edit, it should say the
- offset (pos) in hex.
-
- I did the patch in Turbo Pascal 7, most would probably do it in Asm
- :). Anyway, here is the patch:
-
- ---------------------------------------------------------------------
- ---------------------------------------------------------------------
-
- Program Patcher;
-
- Uses Crt;
-
- Const offset : Longint = $2D86; { $ means a hex value }
- bytes : Byte = 2;
- len : Longint = 51200; { file length }
- orgbytes : Array[1..2] Of Byte = ($74, $09);
- newbytes : Array[1..2] Of Byte = ($EB, $2A);
- {---------------------------------------------------------}
- filename : String[12] = 'DESKEY.EXE';
- errnof : String[43] = ' ERROR: File DESKEY.EXE was not found.';
- errver : String[36] = ' ERROR: File size is not correct.';
- errpch : String[36] = ' ERROR: File seems to be patched.';
- msgdon : String[21] = ' Patch successful!';
- ask : String[26] = ' Continue anyway? (Y/N)';
-
- Procedure message(message : String);
- Begin
-
- WriteLn;
- WriteLn(message);
- Halt;
-
- End;
-
- Procedure patchfile;
- Var fil : File Of Byte;
- teck : Byte;
- n : Byte;
- ch : Char;
- Begin
-
- Assign(fil, filename);
-
- {$I-}
- Reset(fil);
- {$I+}
-
- If (Not(IOResult=0)) Then message(errnof);
- If (Not(FileSize(fil)=len)) Then
- Begin
-
- WriteLn;
- WriteLn(errver);
- WriteLn(ask);
- Repeat Until Keypressed;
-
- ch:=ReadKey;
-
- If Upcase(ch)='N' Then Halt;
-
- End;
-
- Seek(fil, offset);
-
- For n:=1 To bytes Do
- Begin
-
- Read(fil, teck);
- If (Not(teck=orgbytes[n])) Then message(errpch);
-
- End;
-
- Seek(fil, offset);
- For n:=1 To bytes Do Write(fil, newbytes[n]);
- Close(fil);
-
- WriteLn;
- WriteLn(msgdon);
-
- Halt;
-
- End;
-
- Begin
-
- WriteLn;
- WriteLn(' SoftArts Deskey v1.02.010 Patch');
- WriteLn(' By ODIN / RBS^TFT^PIE in 1997');
- patchfile;
-
- End.
-
- ---------------------------------------------------------------------
- ---------------------------------------------------------------------
-
- Some final words.
-
- Take some programs and play with patching them in various ways. This
- gives you experience, and hopefully you'll become a better cracker.
-
- Thanks to Qapla, kOUGER, Hook and Tgunner for help while making this
- tutorial.
-
- A special greeting goes to ED!SON.
-
- 6. THE URL'S
-
- My E-Mail : cracking@usa.net
- SoftArts Deskey v1.02.010 : http://www.spiresoft.com
- Ultra Edit vX : http://www.windows95.com/apps/
-